
package com.thinkgem.jeesite.common.pojo.auth.access.interceptor;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.thinkgem.jeesite.common.pojo.auth.access.annotation.AccessLacks;
import com.thinkgem.jeesite.common.pojo.auth.access.annotation.AccessNeeded;
import com.thinkgem.jeesite.common.pojo.auth.access.ic.AccessProcess;
import com.thinkgem.jeesite.common.pojo.auth.access.process.AnnoProcess;
import com.thinkgem.jeesite.common.pojo.auth.access.process.LacksProcess;
import com.thinkgem.jeesite.common.pojo.auth.access.process.NeededProcess;
import com.thinkgem.jeesite.common.pojo.auth.access.type.Relation;

/**
 * access相关tag的拦截器,将注解信息提取并校验
 *
 */
public class AccessInterceptor extends HandlerInterceptorAdapter {
	final Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * handler预处理,访问检查拦截器
	 */
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		logger.debug("Access check...");

		AccessNeeded accessNeeded = getAccessNeeded(handler); //获取被拦截对象的need注解
		AccessLacks accessLacks = getAccessLacks(handler);    //获取被拦截对象的lack注解

		//annotation检测,如果不是accessneed或accesslacks则直接跳出,否则继续(即:这里只处理对应的注解项)
		return AnnoProcess.relationCheck(Relation.OR,
				checkAnnotation(request,response,accessNeeded),
				checkAnnotation(request,response,accessLacks));
	}

	/**
	 * 初始化,读取注解@AccessNeeded
	 * @param handler
	 * @return 对应注解项
	 * 2015年5月23日
	 */
	private AccessNeeded getAccessNeeded(Object handler){
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();
		return method.getAnnotation(AccessNeeded.class);
	}

	/**
	 * 初始化,读取注解@AccessLacks
	 * @param handler
	 * @return 对应注解项
	 * 2015年5月23日
	 */
	private AccessLacks getAccessLacks(Object handler){
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();
		return method.getAnnotation(AccessLacks.class);
	}

	/**
	 * need注解检查.找到need后填写token,并启动need处理器
	 * @param request      http请求消息
	 * @param response     http响应消息
	 * @param accessNeeded need注解项
	 * @return 检查结果
	 * @throws Exception
	 * 2015年5月23日
	 */
	private boolean checkAnnotation(HttpServletRequest request,
			HttpServletResponse response,AccessNeeded accessNeeded) throws Exception{
		if(accessNeeded != null){//找到注解,进行检测
			return checkAnnotation(request,response,
			        new NeededProcess(accessNeeded),
					"accesse_needed_token");
		}else{//没有找到注解,直接通过
			return true;
		}
	}

	/**
	 * lack注解检查.找到lack后填写token,并启动lack处理器
	 * @param request      http请求消息
	 * @param response     http响应消息
	 * @param accessLacks  lack注解项
	 * @return 检查结果
	 * @throws Exception
	 * 2015年5月23日
	 */
	private boolean checkAnnotation(HttpServletRequest request,
			HttpServletResponse response,AccessLacks accessLacks) throws Exception{
		if(accessLacks != null){//找到注解,进行检测
			return checkAnnotation(request,response,
					new LacksProcess(accessLacks),
					"accesse_lacks_token");
		}else{//没有找到注解,直接通过
			return true;
		}
	}

	/**
	 * 根据访问处理器和token来完成注解检查.
	 * @param request      http请求消息
	 * @param response     http响应消息
	 * @param access       访问处理器
	 * @param tokenInfo    token项
	 * @return 检查结果
	 * @throws Exception
	 * 2015年5月23日
	 */
	private boolean checkAnnotation(HttpServletRequest request,
			HttpServletResponse response,AccessProcess access,String tokenInfo) throws Exception{
		// 查看当前session的用户是否具有token标记,如果没有,进入后续流程,有的话直接跳过拦截器
		HttpSession session = request.getSession();
		String token = (String)session.getAttribute(tokenInfo);
		if(!token.equals("accessed")){//token不匹配或者没有找到token时需要检测
			System.out.println("process: @AccessProcess");
			if(access.annoCheck()){//如果通过访问注解检测,将token写入session
				session.setAttribute(tokenInfo, "accessed");
				return true;
			}else{// 注解没有通过拦截,权限不足
				response.getWriter().write("没有通过拦截，权限不足.");
				return false;
			}
		}else{//找到了token,已经完成检测,直接通过
			return true;
		}
	}
}
